package com.example.hello.POJO;

import com.example.hello.views.users.Users;

import java.util.*;

public class UserPOJO extends POJO {

    public enum Role {
        BASIC, REVIEWER, ASSIGNMENT_ADMIN, SITE_ADMIN
    }

    private String firstName;
    private String lastName;
    private String userName;
    private String password;
    private String email;
    private boolean siteAdmin;
    private int reputation;
    private List<String> badges = new ArrayList<>();
    private Set<String> organizations = new HashSet<>();
    private Set<String> assignments = new HashSet<>();
    private Set<String> assignedOrgs = new HashSet<>();

    public UserPOJO() {
        siteAdmin = false;
    }

    public UserPOJO(String userName, String password) {
        this("firstName", "lastName", userName, password);
    }

    public UserPOJO(String firstName, String lastName, String userName, String password) {
        this(firstName, lastName, userName, password, "", false);
    }

    public UserPOJO(String firstName, String lastName, String userName, String password, String email, boolean siteAdmin) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.userName = userName;
        this.password = password;
        this.email = email;
        this.siteAdmin = siteAdmin;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getFullName(boolean reverse) {
        if (reverse)
            return lastName + ", " + firstName;
        else
            return firstName + " " + lastName;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getName() {
        return userName;
    }

    public void setName(String name) {
        setUserName(name);
    }

    public String getDecodedName() {
        return userName;
    }

    public String getEncodedName() {
        return userName;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public boolean isSiteAdmin() {
        return siteAdmin;
    }

    public void setSiteAdmin(boolean siteAdmin) {
        this.siteAdmin = siteAdmin;
    }

    public String getRoles() {
        String roles = "";
        if (!organizations.isEmpty()) roles += Role.BASIC;
        if (!assignments.isEmpty())
            if (!roles.equals("")) {
                roles += ", ";
            } else {
                roles += Role.REVIEWER;
            }
        if (!assignedOrgs.isEmpty())
            if (!roles.equals("")) {
                roles += ", ";
            } else {
                roles += Role.ASSIGNMENT_ADMIN;
            }
        return roles;
    }

    public Role getRole(AssignmentPOJO assignment) {
        if (siteAdmin) return Role.SITE_ADMIN;
        if (assignments.contains(assignment.getEncodedName()))
            return Role.REVIEWER;
        else
            return Role.BASIC;
    }

    public Role getRole(OrganizationPOJO org) {
        if (siteAdmin) return Role.SITE_ADMIN;
        if (assignedOrgs.contains(org.getEncodedName()))
            return Role.ASSIGNMENT_ADMIN;
        else
            return Role.BASIC;
    }

    public Role getOrgRole(String org) {
        if (siteAdmin) return Role.SITE_ADMIN;
        if (assignedOrgs.contains(org))
            return Role.ASSIGNMENT_ADMIN;
        else
            return Role.BASIC;
    }

    public Role getAssignmentRole(String assignment) {
        if (siteAdmin) return Role.SITE_ADMIN;
        if (assignments.contains(assignment))
            return Role.ASSIGNMENT_ADMIN;
        else
            return Role.BASIC;
    }

    public int getReputation() {
        return reputation;
    }

    public void setReputation(int reputation) {
        this.reputation = reputation;
    }

    public List<String> getBadges() {
        return badges;
    }

    public void setBadges(List<String> badge) {
        this.badges = badge;
    }

    public void addBadge(String badge) {
        if (!badges.contains(badge)) badges.add(badge);
    }

    public boolean removeBadge(String badge) {
        return badges.remove(badge);
    }

    public boolean hasBadge(String badge) {
        return badges.contains(badge);
    }

    public Set<String> getOrganizations() {
        return organizations;
    }

    public void setOrganizations(Set<String> organization) {
        this.organizations = organization;
    }

    public void addOrg(String organization) {
        if (!organizations.contains(organization)) organizations.add(organization);
    }

    public boolean removeOrg(String organization) {
        return assignedOrgs.remove(organization);
    }

    public boolean hasOrg(String organization) {
        return assignedOrgs.contains(organization);
    }

    public Set<String> getAssignments() {
        return assignments;
    }

    public void setAssignments(Set<String> assignment) {
        this.assignments = assignment;
    }

    public void addAssignment(String assignment) {
        if (!assignments.contains(assignment)) assignments.add(assignment);
    }

    public boolean removeAssignment(String assignment) {
        return assignments.remove(assignment);
    }

    public boolean hasAssignment(String assignment) {
        return assignments.contains(assignment);
    }

    public Set<String> getAssignedOrgs() {
        return assignedOrgs;
    }

    public void setAssignedOrgs(Set<String> assignedOrg) {
        this.assignedOrgs = assignedOrg;
    }

    public void addAssignedOrg(String assignedOrg) {
        if (!assignedOrgs.contains(assignedOrg)) assignedOrgs.add(assignedOrg);
    }

    public boolean removeAssignedOrg(String assignedOrg) {
        return assignedOrgs.remove(assignedOrg);
    }

    public boolean hasAssignedOrg(String assignedOrg) {
        return assignedOrgs.contains(assignedOrg);
    }

    public String toString() {
        String str = "User:\n";

        str += "    _id: " + _id + "\n";
        str += "    name: " + firstName + " " + lastName + "\n";
        str += "    userName: " + userName + "\n";
        str += "    password: " + password + "\n";
        str += "    email: " + email + "\n";
        str += "    isSiteAdmin: " + siteAdmin + "\n";
        str += "    roles: " + getRoles() + "\n";
        str += "    reputation: " + reputation + "\n";
        str += "    badges: " + Arrays.toString(badges.toArray());
        if (!organizations.isEmpty())
            str += "\n    organizations: " + Arrays.toString(organizations.toArray());
        if (!assignments.isEmpty())
            str += "\n    assignments: " + Arrays.toString(assignments.toArray());
        if (!assignedOrgs.isEmpty())
            str += "\n    assignedOrgs: " + Arrays.toString(assignedOrgs.toArray());

        return str;
    }

    /**
     * Since Users have a different "business key" variable name than the other POJOs
     * (although, quite similar in nature), the compareTo method must be
     * overridden for correct use when sorting.
     */
    @Override
    public int compareTo(Object o) {
        return userName.compareToIgnoreCase(((UserPOJO) o).getUserName());
    }

    public boolean create() {
        return create(Users.NAME, this);
    }

    public boolean update() {
        return update(Users.NAME + "/" + name, this);
    }

}